﻿#include "AI_httpAPI.h"
#include <hv/hv.h>
#include <hv/HttpServer.h>
#include <hv/HttpService.h>
#include <time.h>


#define DEFAULT_PACKAGE_MAX_LENGTH (1<<21)
timed_mutex mtx0;
mutex mtx1;
stringstream ll2;


void AIhttp::open(int port)
{
	if (port == 0)
		port = 8080;
	cout << "Server OPEN , port: " << port << endl;
	//router.api_handlers
	Router::Register(router);
	start = true;

	http_server_t server;
	server.service = &router;
	server.port = port;

	while (start)
		http_server_run(&server);


}

void AIhttp::close()
{
	start = false;
}







int _Exist_Recognize_rtsp(json& reqBody)
{
	Logger logger2(Logger::file_and_terminal, Logger::debug, "..\\logs\\AIhttpLog.txt");
	//unique_lock<timed_mutex> lck(mtx0, chrono::duration<double, deca>(1));//改成try
	unique_lock<mutex> lck(mtx1, try_to_lock);
	if (!lck.owns_lock()) {
		ll2.str("");
		ll2 << __LOCATION__;
		logger2.ERRORS("Exist Recognize is running, kill this thread",ll2.str()); 
		return 1;
	}
	/*    输入数据：json==>exist_params    */
	PARAMS_EXIST p_exist;
	InputData::EXIST_RECOGNIZE(reqBody, p_exist);

	string rtspUrl = p_exist.videoUrl;

	//识别
	int ret = Exist_rtsp(rtspUrl,  p_exist.recognizeTime, p_exist.classId);
	/*if (ret != 0) {
		
		cerr << "Exist Recognize => FAILED" << endl;
		cerr << "Programe break" << endl;
		return -1;
	}*/
	ll2.str("");
	ll2 << __LOCATION__;
	logger2.DEBUG("Exist Recognize return",ll2.str());
	cout << "Exist Recognize return" << endl;
	return 0;
}

//封装到类里面

template<typename T>
inline void CheckEmpty(const T &vec)
{
	if (vec.empty())
		cerr << "InputData vector is empty." << endl;
}

inline void Download_Error_LOG(const int ret, string path, string url, string cur_path)
{
	if (ret == 0) {
		return;
	}
	else {
		cerr << "Download Picture failed" << endl;
		string logName = cur_path + "\\error_log.txt";
		stringstream log;
		ofstream error_log(logName);

		switch (ret)
		{

		case 1: {
			cerr << "Create File Error, Please Check <file_path>:" << path << endl;
			log.str("");
			log << "ERROR:1  Create file fail, check path:" << path << endl;
			error_log << log.str();
			error_log.close();
			return;
		}
		case 2: {
			cerr << "Request Error, Please Check <url>:" << url << endl;
			log.str("");
			log << "ERROR:2  Picture url fail, check url:" << url << endl;
			error_log << log.str();
			error_log.close();
			return;
		}
		case 3: {
			cerr << "Download File Error, Please Check <url> or <request/response>" << endl;
			log.str("");
			log << "ERROR:3  Download Break Off, URL:" << url << endl;
			error_log << log.str();
			error_log.close();
			return;
		}
		}
	}


}


bool CheckUrl(string url)
{
	if (!url.empty()) {
		requests::Request reqUrl(new HttpRequest);//智能指针，自动释放
		reqUrl->url = url;
		reqUrl->method = HTTP_GET;
		reqUrl->SetRange(0, 1);

		auto respUrl = requests::request(reqUrl);
		if (respUrl->status_code == HTTP_STATUS_BAD_REQUEST || respUrl->status_code == HTTP_STATUS_FORBIDDEN || respUrl == NULL) {
			return false;
		}

		return true;//正确返回true
	}
	else
		return false;
}

int Download(const string file_path, const string url)
{
	cout << "Download file to " << file_path << endl;
	HFile file;
	if (file.open(file_path.c_str(), "wb") != 0) {
		return 1;
	}

	//请求头
	requests::Request req(new HttpRequest);
	req->url = url;
	req->method = HTTP_GET;
	req->SetRange(0, 1);
	auto resp = requests::request(req);
	if (resp == NULL) {
		file.close();
		return 2;
	}
	//cout << "resp:\n" << resp->Dump(true, false) << endl;

	//获取数据总长度
	string str = resp->GetHeader("Content-Range");
	int pos = str.find_last_of('/');
	string content_length = str.substr(pos + 1);
	size_t length = _atoi64(content_length.c_str());
	cout << "content-length: " << (length >> 20) << "MB" << endl;

	//下载数据
	long from, to;
	from = 0;
	int range_bytes = DEFAULT_PACKAGE_MAX_LENGTH;//2MB
	http_client_t* cli = http_client_new();
	int sec = 0;
	//计时
	clock_t start, end;
	start = clock();

	while (from < length) {
		++sec;
		if (sec % 15 == 0) {
			end = clock();
			double time = (double)(end - start) / CLOCKS_PER_SEC;
			cout << "download... " << sec << "MB cost " << time << "secs ..." << endl;
		}
		to = from + range_bytes - 1;
		if (to >= length) to = length - 1;
		req->SetRange(from, to);
		int ret = http_client_send(cli, req.get(), resp.get());
		if (ret != 0) {
			file.close();
			return 3;
		}
		file.write(resp->body.data(), resp->body.size());
		from = to + 1;
	}

	http_client_del(cli);
	file.close();

	cout << "download finish !!!" << endl;
	return 0;
}

int _Config(json& reqBody)
{
	/****    输入数据：json==>config_params    ****/
	PARAMS_CONF p_conf;
	InputData::CONF(reqBody, p_conf);
	CheckEmpty(p_conf.faceList);

	/****    处理数据：config_params    ****/
	vector<string> vecImgPath;//图片保存地址

	char buff[1000];
	string cur_path;
	cur_path = getcwd(buff, 1000);//当前目录，长度不超过1000
	string folderPath = "..\\resource\\DownloadPicture\\" + p_conf.classId;  //创建班级的文件夹
	if (0 != access(folderPath.c_str(), 0))
		mkdir(folderPath.c_str());


	for (auto &each_user : p_conf.faceList) {
		string url = each_user.faceUrl;
		if (!CheckUrl(url)) {
			cerr << "Please check the url: " << each_user.faceUrl << endl;
			continue;
		}

		string name = each_user.usrId;
		string imgPath = folderPath + "\\" + name + ".jpeg";
		int ret = Download(imgPath, url);
		Download_Error_LOG(ret, imgPath, url, folderPath);//下载异常处理
		vecImgPath.push_back(imgPath);
	}

	int ret = FR_ExportFeature(vecImgPath, p_conf.faceList, p_conf.featList);//结果：featList
	if (ret != 0) {
		cerr << "ExportFeature failed" << endl;
		return -1;
	}

	/****    输出数据：config_params==>string    ****/
	json resJson;
	OutputData::CONF(resJson, p_conf);

	string bkr = "192.168.13.223:9092";
	string top = "ai-web-config";
	KafkaProducer *Kafkapr = new KafkaProducer(bkr, top);
	Kafkapr->Init();
	string resStr = resJson.dump();
	Kafkapr->Send(resStr);
	delete Kafkapr;
	cout << "Picture Config Success\n";

	//保存数据(传回的数据)
	string fileName = "..\\resource\\jsonData\\CONF_Res.json";
	ofstream file(fileName);
	if (file.fail())
		cout << "Create file fail" << endl;
	file << resJson.dump(4);
	file.close();

	return 0;
}



void save_request(json reqBody)
{
	string path = "..\\logs\\RequestsBody.json";
	fstream file(path, ios::out | ios::app);
	char tmp[64];
	time_t ptime;
	time(&ptime);  // time_t time (time_t* timer);
	tm ptm;
	localtime_s(&ptm, &ptime);
	strftime(tmp, sizeof(tmp), "%Y-%m-%d %H:%M:%S", &ptm);
	json a = reqBody;
	string str(tmp);
	a["time"] = str;
	
	file << a.dump(4) << endl;
	file.close();
}